#! /bin/bash

# 获取站点列表
get_server_list() {
  list=`ls $CONFDIR | grep -E ".conf(\.bak)?$"`
  printf "%-10s %-32s %-52s %-22s %-22s\n" "PID" "名称" "域名" "端口" "证书到期"
  echo "------------------------------------------------------------------------------------------------------------------------------------------"
  for file in ${list[@]}
  do
    pid=`get_pid $file`
    name=`get_name $file`
    domain=`get_info_node $CONFDIR/$file server_name`
    ipv4=(`get_info_node $CONFDIR/$file listen "|ssl|http2"`)
    cert=`get_info_node $CONFDIR/$file ssl_certificate`
    enddate=`get_cert_enddate "$cert" "+%Y-%m-%d %H:%M:%S"`
    printf "%-10s %-30s %-50s %-20s %-20s\n" "$pid" "$name" "$domain" "${ipv4[*]}" "$enddate"
    unset pid name domain ipv4 cert enddate
  done
  unset list file
}

# 从配置中获取节点属性
get_info_node() {
  if [[ ! -f $1 ]]; then
    return
  fi
  if [[ $2 == 'listen' ]]; then
    cat $1 | grep -E "\s+$2\s+[0-9]{2,5}" | sed -E "s/$2$3//g" | sed -E "s/^(\s+)|\;//g" | uniq
  else
    cat $1 | grep -E "\s+($2)\s+" | sed -E "s/($2)//" | sed -E "s/^(\s+)|\;//g" | sed -n "1p" | uniq
  fi
}

# 获取证书到期时间
get_cert_enddate() {
  if [[ ! -n $1 || ! -f $1 ]]; then
    echo "--"
    return
  fi
  date --date="$(openssl x509 -in $1 -noout -enddate | sed 's/\(.*\)=\(.*\)/\2/g')" "$2"
}

# 获取排序ID
get_pid() {
  if [[ -n $(echo "$1" | grep -o '\[.*\]' | sed -E 's/\[|\]//g') ]]; then
    echo "$1" | grep -o '\[.*\]' | sed -E 's/\[|\]//g'
  else
    echo "--"
  fi
}

# 获取名称
get_name() {
  echo $1 | sed -E "s/\.(conf|hash)(\.bak)?$//" | sed -E "s/^\[[0-9a-z]{1,2}\]//"
}

# 创建站点配置
create_server() {
  unset name domain port wwwroot
  while [ ${#} -gt 0 ]; do
    case "${1}" in
    --name)
      name=$2
      shift
    ;;
    --domain)
      if [[ -n $domain ]]; then
        domain="$domain,$2"
      else
        domain=$2
      fi
      shift
    ;;
    --port)
      port=$2
      shift
    ;;
    --wwwroot)
      wwwroot=$2
      shift
    ;;
    *)
      echo -e "${red}Unknown parameter : $1${plain}"
      return 1
      shift
    ;;
    esac
    shift 1
  done
  file="$CONFDIR/$name.conf"
  # 创建配置
  echo -e "" > $file
  echo -e "server {" >> $file
  echo -e "    listen $port;" >> $file
  echo -e "    listen [::]:$port;" >> $file
  echo -e "    server_name $(echo $domain | sed 's/\,/ /g');" >> $file
  if [[ -n $wwwroot ]]; then
    echo -e "    root $wwwroot;" >> $file
    echo -e "    index index.html index.htm index.php;" >> $file
  fi
  echo -e "    " >> $file
  echo -e "    include $WORKDIR/proxy/$name/*.conf;" >> $file
  echo -e "    " >> $file
  echo -e "    # 日志" >> $file
  echo -e "    access_log $WORKDIR/logs/$name/access.log;" >> $file
  echo -e "    error_log $WORKDIR/logs/$name/error.log;" >> $file
  echo -e "}" >> $file
  # 创建文件
  mkdir -p "$WORKDIR/proxy/$name"
  mkdir -p "$WORKDIR/logs/$name"
  if [[ -n $wwwroot ]]; then
    mkdir -p "$wwwroot"
    if [[ ! -f "$wwwroot/index.html" ]]; then
      wget --no-check-certificate -qO "$wwwroot/index.html" $KENOTE_BASH_MIRROR/nginx/html/index.html
    fi
  fi
  unset name domain port wwwroot file
}

# 设置SSL证书
set_ssl_certificate() {
  file="$CONFDIR/$1"
  if [[ -n $(get_info_node $file ssl_certificate) ]]; then
    return
  fi
  domain=`get_info_node $file server_name | awk -F " " '{print $1}'`
  port=`get_info_node $file listen | sed -n 1p`
  echo "http://$domain:$port"
  local_version=$(curl -s -I http://$domain:$port | grep -i "^server:" | awk -F "/" '{print $2}')
  if [[ ! -n $(printf '%s\n' "$local_version" "1.25" | sort -V | head -n1 | grep "1.25") ]]; then
    http2="http2"
  fi
  cp $file "$file.http"
  # 添加HTTPS配置
  echo -e "" > $file
  echo -e "server {" >> $file
  echo -e "    listen $(get_info_node "$file.http" listen | sed -n 1p);" >> $file
  echo -e "    listen [::]:$(get_info_node "$file.http" listen | sed -n 1p);" >> $file
  echo -e "    server_name $(get_info_node "$file.http" server_name);" >> $file
  if [[ -n $(get_info_node "$file.http" root) ]]; then
    echo -e "    root $(get_info_node "$file.http" root | sed -n 1p);" >> $file
  fi
  if [[ -n $(get_info_node "$file.http" index) ]]; then
    echo -e "    index $(get_info_node "$file.http" index | sed -n 1p);" >> $file
  fi
  echo -e "    " >> $file
  echo -e "    # 日志" >> $file
  echo -e "    access_log $(get_info_node "$file.http" access_log);" >> $file
  echo -e "    error_log $(get_info_node "$file.http" error_log);" >> $file
  echo -e "}" >> $file
  echo -e "" >> $file
  echo -e "server {" >> $file
  echo -e "    listen 443 ssl $http2;" >> $file
  echo -e "    listen [::]:443 ssl $http2;" >> $file
  echo -e "    server_name $(get_info_node "$file.http" server_name);" >> $file
  if [[ -n $(get_info_node "$file.http" root) ]]; then
    echo -e "    root $(get_info_node "$file.http" root | sed -n 1p);" >> $file
  fi
  if [[ -n $(get_info_node "$file.http" index) ]]; then
    echo -e "    index $(get_info_node "$file.http" index | sed -n 1p);" >> $file
  fi
  echo -e "    " >> $file
  if [[ ! -n $http2 ]]; then
    echo -e "    http2 on;" >> $file
  fi
  echo -e "    " >> $file
  echo -e "    ssl_certificate $2;" >> $file
  echo -e "    ssl_certificate_key $3;" >> $file
  echo -e "    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;" >> $file
  echo -e "    ssl_prefer_server_ciphers on;" >> $file
  echo -e "    ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;" >> $file
  echo -e "    ssl_session_cache shared:SSL:5m;" >> $file
  echo -e "    ssl_session_timeout 5m;" >> $file
  echo -e "    " >> $file
  cat "$file.http" | grep -E "\s+include\s+" | uniq >> $file
  echo -e "    " >> $file
  echo -e "    # 日志" >> $file
  echo -e "    access_log $(get_info_node "$file.http" access_log);" >> $file
  echo -e "    error_log $(get_info_node "$file.http" error_log);" >> $file
  echo -e "}" >> $file
  unset file domain port local_version
}

# 站点选项
server_options() {
  clear
  file="$CONFDIR/$1"
  ipv4=(`get_info_node $file listen "|ssl|http2"`)
  echo "站点 -- $(get_name $1)"
  echo "------------------------"
  echo "绑定域名: $(get_info_node $file server_name)"
  echo "监听端口: ${ipv4[*]}"
  echo "证书到期: $(get_cert_enddate "$(get_info_node $file ssl_certificate)" "+%Y-%m-%d %H:%M:%S")"
  echo
  get_proxy_list "$(get_name $1)"
  
  echo
  echo "操作选项"
  echo "----------------------------------------------------------------"
  echo "1. 设置附加参数         2. 设置排序编号         3. 签发免费证书"
  echo "4. 添加虚拟目录         5. 添加反向代理         6. 设置FastCGI"
  echo "7. 添加文件缓存         8. 编辑代理模型         9. 删除代理模型"
  echo "----------------------------------------------------------------"
  echo "11. 重启应用配置        12. 检测站点配置        13. 手动编辑配置"
  echo "14. 删除站点配置"
  echo "----------------------------------------------------------------"
  echo "0. 返回上一级"
  echo "------------------------"
  echo
  if [[ -n $3 ]]; then
    echo -e "${red}$3${plain}"
    echo
  fi
  file="$CONFDIR/$1"
  read -p "请输入选择: " sub_choice

  case $sub_choice in
  1)
    clear
    echo "设置附加参数"
    echo "------------------------"
    echo "加载中..."
    echo
    sleep 3
    filename=`ls $WORKDIR/proxy/$(get_name $1) | grep -E "^(\[[0-9]{1,2}\])?setting\.conf(\.bak)?$"`
    if [[ -n $filename ]]; then
      vi $WORKDIR/proxy/$(get_name $1)/$filename
      unset filename
    else
      set_http_setting --server "$(get_name $1)"
    fi
    clear
    server_options $1 $2
  ;;
  2)
    clear
    sub_title="设置排序编号 -- $(get_name $1)\n------------------------"
    echo -e $sub_title
    while read -p "排序编号: " pid
    do
      goback $pid "clear;server_options $1 $2"
      if [[ ! -n $pid ]]; then
        warning "请输入新的排序编号！" "$sub_title"
        continue
      fi
      if [[ ! -n $(echo $pid | gawk '/^[0-9a-z]{2}$/{print $0}') ]]; then
        warning "排序编号必须长度为2位的数字加英文字符！" "$sub_title"
        continue
      fi
      break
    done
    sub_title="$sub_title\n排序编号: $pid"
    clear && echo -e $sub_title
    echo
    mv $file "$CONFDIR/[$pid]$(get_name $1).conf"
    echo -e "- 排序编号已设置为 [${green}$pid${plain}]"
    echo
    read -n1 -p "按任意键继续" key
    clear
    server_options "[$pid]$(get_name $1).conf" $2
  ;;
  3)
    clear
    echo "签发免费证书"
    echo "------------------------"
    echo
    if [[ -n $(get_info_node $file server_name | grep "localhost") ]]; then
      echo -e "- ${yellow}绑定域名中存在本地配置，无法签发证书${plain}"
      echo
      read -n1 -p "按任意键继续" key
      clear
      server_options $1 $2
      return
    fi
    confirm "确定要签发免费证书吗?" "n"
    if [[ $? == 1 ]]; then
      clear
      server_options $1 $2
      return
    fi
    if [[ ! -f $KENOTE_ACMECTL ]]; then
      echo
      echo -e "- ${yellow}请先安装ACME.SH${plain}"
      echo
      read -n1 -p "按任意键继续" key
      clear
      server_options $1 $2
      return
    fi
    if [[ -n $(get_info_node $file ssl_certificate) ]]; then
      echo
      confirm "证书已经存在，是否需要更新?" "n"
      if [[ $? == 1 ]]; then
        clear
        server_options $1 $2
        return
      fi
    fi
    echo
    # 签发证书
    issue_cert_nginx $(get_info_node $file server_name)
    # 安装证书
    cert=`$KENOTE_ACMECTL --list  | grep -E "^$(get_info_node $file server_name | awk -F " " '{print $1}')\s+" | awk -F " " '{print $1}'`
    if [[ -n $cert ]]; then
      # 更换证书配置
      set_ssl_certificate $1 "$KENOTE_SSL_PATH/$cert/cert.crt" "$KENOTE_SSL_PATH/$cert/private.key"
      # 安装证书
      install_cert_nginx $cert
    else
      echo
      echo -e "- ${yellow}证书签发失败${plain}"
    fi
    echo
    read -n1 -p "按任意键继续" key
    clear
    server_options $1 $2
  ;;

  4)
    clear
    sub_title="添加虚拟目录\n------------------------"
    echo -e $sub_title
    echo
    while read -p "映射路径(/): " name
    do
      goback $name "clear;server_options $1 $2"
      if [[ ! -n $name ]]; then
        name="/"
      fi
      break
    done
    sub_title="$sub_title\n映射路径(/): ${name[*]}"
    clear && echo -e $sub_title
    while read -p "物理路径: " wwwroot
    do
      goback $wwwroot "clear;server_options $1 $2"
      if [[ ! -n $wwwroot ]]; then
        warning "请输入指向的物理路径！" "$sub_title"
        continue
      fi
      wwwroot=`parse_path $wwwroot`
      break
    done
    sub_title="$sub_title\n物理路径: $wwwroot"
    clear && echo -e $sub_title
    while read -p "防盗链域名: " valid_referers
    do
      goback "${valid_referers[*]}" "clear;server_options $1 $2"
      if [[ -n $valid_referers ]]; then
        is_param_true "is_domain" "${valid_referers[*]}"
        if [[ $? == 1 ]]; then
          warning "防盗链域名中存在格式错误" "$sub_title"
          continue
        fi
      fi
      break
    done
    sub_title="$sub_title\n防盗链域名: ${valid_referers[*]}"
    clear && echo -e $sub_title
    confirm "是否开启文件索引?" "n"
    if [[ $? == 0 ]]; then
      autoindex="on"
    fi
    echo
    create_virtual_list --server "$(get_name $1)" --name "${name[*]}" --wwwroot "$wwwroot" --valid_referers "${valid_referers[*]}" --autoindex "$autoindex"
    clear
    server_options $1 $2
  ;;
  5)
    clear
    sub_title="添加反向代理\n------------------------"
    echo -e $sub_title
    echo
    while read -p "映射路径(/): " name
    do
      goback $name "clear;server_options $1 $2"
      if [[ ! -n $name ]]; then
        name="/"
      fi
      break
    done
    sub_title="$sub_title\n映射路径(/): ${name[*]}"
    clear && echo -e $sub_title
    while read -p "代理地址: " uri
    do
      goback $uri "clear;server_options $1 $2"
      if [[ ! -n $uri ]]; then
        warning "请输入代理地址！" "$sub_title"
        continue
      fi
      if [[ ! -n $(is_url $uri) ]]; then
        warning "请输入正确的代理地址！" "$sub_title"
        continue
      fi
      break
    done
    sub_title="$sub_title\n代理地址: $uri"
    clear && echo -e $sub_title
    echo
    create_reverse_proxy --server "$(get_name $1)" --name "${name[*]}" --uri "$uri"
    clear
    server_options $1 $2
  ;;
  6)
    clear
    sub_title="设置FastCGI\n------------------------"
    echo -e $sub_title
    echo
    while read -p "FastCGI(127.0.0.1:9000): " fastcgi
    do
      goback $fastcgi "clear;server_options $1 $2"
      if [[ ! -n $fastcgi ]]; then
        fastcgi="127.0.0.1:9000"
      fi
      break
    done
    sub_title="$sub_title\nFastCGI: $fastcgi"
    clear && echo -e $sub_title
    echo
    set_fast_cgi --server "$(get_name $1)" --fastcgi "$fastcgi"
    clear
    server_options $1 $2
  ;;
  7)
    clear
    sub_title="添加文件缓存\n------------------------"
    echo -e $sub_title
    echo
    while read -p "文件类型: " name
    do
      goback $name "clear;server_options $1 $2"
      if [[ ! -n $name ]]; then
        warning "请输入文件类型！" "$sub_title"
        continue
      fi
      break
    done
    sub_title="$sub_title\n文件类型: ${name[*]}"
    clear && echo -e $sub_title
    while read -p "缓存时间: " expires
    do
      goback $expires "clear;server_options $1 $2"
      if [[ ! -n $expires ]]; then
        warning "请设置缓存时间！" "$sub_title"
        continue
      fi
      break
    done
    sub_title="$sub_title\n缓存时间: $expires"
    clear && echo -e $sub_title
    echo
    create_file_cache --server "$(get_name $1)" --name "${name[*]}" --expires "$expires"
    clear
    server_options $1 $2
  ;;

  8)
    clear
    sub_title="编辑代理模型\n------------------------"
    echo -e $sub_title
    echo
    get_proxy_list "$(get_name $1)"
    echo
    while read -p "模型名称: " name
    do
      goback $name "clear;server_options $1 $2"
      if [[ ! -n $name ]]; then
        warning "请输入模型名称！" "$sub_title" "get_proxy_list \"$(get_name $1)\""
        continue
      fi
      if [[ ! -n $(ls $WORKDIR/proxy/$(get_name $1) | grep -E "^(\[[0-9]{1,2}\])?$name\.conf(\.bak)?$") ]]; then
        warning "输入的模型不存在" "$sub_title" "get_proxy_list \"$(get_name $1)\""
        continue
      fi
      filename=`ls $WORKDIR/proxy/$(get_name $1) | grep -E "^(\[[0-9]{1,2}\])?$name\.conf(\.bak)?$"`
      break
    done
    echo
    vi $WORKDIR/proxy/$(get_name $1)/$filename
    unset name filename
    clear
    server_options $1 $2
  ;;
  9)
    clear
    sub_title="删除代理模型\n------------------------"
    echo -e $sub_title
    echo
    get_proxy_list "$(get_name $1)"
    echo
    while read -p "模型名称: " name
    do
      goback $name "clear;server_options $1 $2"
      if [[ ! -n $name ]]; then
        warning "请输入模型名称！" "$sub_title" "get_proxy_list \"$(get_name $1)\""
        continue
      fi
      if [[ ! -n $(ls $WORKDIR/proxy/$(get_name $1) | grep -E "^(\[[0-9]{1,2}\])?$name\.conf(\.bak)?$") ]]; then
        warning "输入的模型不存在" "$sub_title" "get_proxy_list \"$(get_name $1)\""
        continue
      fi
      filename=`ls $WORKDIR/proxy/$(get_name $1) | grep -E "^(\[[0-9]{1,2}\])?$name\.conf(\.bak)?$"`
      break
    done
    echo
    confirm "确定要删除代理模型吗?" "n"
    if [[ $? == 0 ]]; then
      rm -rf $WORKDIR/proxy/$(get_name $1)/$filename
    fi
    unset name filename
    clear
    server_options $1 $2
  ;;
  11)
    clear
    echo "重启应用配置"
    echo "------------------------"
    echo
    systemctl restart nginx
    systemctl status nginx
    echo
    read -n1 -p "按任意键继续" key
    clear
    server_options $1 $2
  ;;
  12)
    clear
    echo "检测当前配置"
    echo "------------------------"
    echo
    nginx -t
    echo
    read -n1 -p "按任意键继续" key
    clear
    server_options $1 $2
  ;;
  13)
    clear
    vi $file
    clear
    server_options $1 $2
  ;;
  14)
    clear
    echo "删除站点配置"
    echo "------------------------"
    echo
    confirm "确定要删除站点配置吗?" "n"
    if [[ $? == 1 ]]; then
      clear
      server_options $1 $2
      return
    fi
    echo
    wwwroot=`get_info_node $file root | sed -n 1p`
    rm -rf $file
    rm -rf $WORKDIR/proxy/$(get_name $1)
    echo
    confirm "是否同时删除日志和静态文件目录?" "n"
    if [[ $? == 0 ]]; then
      if [[ -n $wwwroot && -f $wwwroot ]]; then
        rm -rf $wwwroot
      fi
      rm -rf $WORKDIR/logs/$(get_name $1)
    fi
    unset wwwroot
    systemctl restart nginx
    systemctl status nginx
    sleep 5
    clear
    show_menu "" $2
  ;;
  0)
    clear
    show_menu "" $2
  ;;
  *)
    clear
    server_options $1 $2 "请输入正确的数字"
  ;;
  esac
  unset file ipv4 sub_choice
}